/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Implementation of YUYV_to_RGB imageformat conversion.
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#include "YUYV_to_RGB.h"

//*****************************************************************************
//*****************************************************************************
//*****************************************************************************

/** YUYV format structure.
 *
 * This structure matches to the pixel representation of YUYV. It
 * contains information for two pixels, which have distinct Y values,
 * but common U and V values.
 */
typedef struct __yuyvmacropixel {
  uint8_t y0;
  uint8_t u;
  uint8_t y1;
  uint8_t v;
} TYUYVMacroPixel;
//*****************************************************************************
//*****************************************************************************

/** Conversion routine from YUV to RGB.
 *
 * Basis of this routine was copied from:
 * http://social.msdn.microsoft.com/Forums/en-US/windowsdirectshowdevelopment/thread/1071301e-74a2-4de4-be72-81c34604cde9
 */
static inline void yuv2rgb(int y, int u, int v, 
                           uint8_t *r, uint8_t *g, uint8_t *b)
{
  int r1, g1, b1;
  int c = y-16, d = u - 128, e = v - 128;       
  
  r1 = (298 * c + 409 * e + 128) >> 8;
  g1 = (298 * c - 100 * d - 208 * e + 128) >> 8;
  b1 = (298 * c + 516 * d + 128) >> 8;
  
  // Even with proper conversion, some values still need clipping.
 
  if (r1 > 255) r1 = 255;
  if (g1 > 255) g1 = 255;
  if (b1 > 255) b1 = 255;
  if (r1 < 0) r1 = 0;
  if (g1 < 0) g1 = 0;
  if (b1 < 0) b1 = 0;
  
  *r = r1 ;
  *g = g1 ;
  *b = b1 ;
}
//*****************************************************************************

void conversion_YUYV_to_RGB (uint8_t *output, 
                             const uint8_t *input,
                             int width, int height)
{
  TYUYVMacroPixel *iptr = (TYUYVMacroPixel *)input;
  uint8_t *optr = output;

  int i;
  for(i=0; i < (width*height)>>1; ++i) {
    uint8_t R,G,B;

    // Take the first pixel (y0), and use the common u and v values.
    yuv2rgb(iptr->y0, iptr->u, iptr->v, &R, &G, &B);
    *optr = R; 
    ++optr;
    *optr = G; 
    ++optr;
    *optr = B; 
    ++optr;

    // Then take the second pixel (y1) and again use the common u and v values.
    yuv2rgb(iptr->y1, iptr->u, iptr->v, &R, &G, &B);
    *optr = R; 
    ++optr;
    *optr = G; 
    ++optr;
    *optr = B; 
    ++optr;

    // Input pointer incremented once per 2 pixels
    ++iptr;
  }
}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
